﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;

using GeneralDFS.Interface.Nodes;
using NIF.MobileActors.Core;

namespace NIF.MobileActors.Hosts
{
    public class RemotingHost// : MarshalByRefObject, IActorHost 
    {
        private static IPEndPoint endPoint = null;
        public static IPEndPoint EndPoint
        {
            get { return endPoint; }
        }
        public static IBaseNode Node { set; get; }

        public static IHostLocal LocalFacade
        {
            get
            {
                return localFacade;
            }
        }

        public static void RegisterLocal(string ip, int port)
        {
            TcpServerChannel channel = new TcpServerChannel("Hello" + port, port);

            try
            {
                ChannelServices.RegisterChannel(channel, false);//向信道服务注册信道
            }
            catch (Exception exception)
            {
                LogUtil.LogError(exception);
            }

            RemotingConfiguration.RegisterWellKnownServiceType(typeof(HostRemotingFacade), RemotingURI, WellKnownObjectMode.Singleton);

            endPoint = new IPEndPoint(IPAddress.Parse(ip), port);

            localFacade = new HostLocalFacade();
            localFacade.Start();
        }

        public static IHostRemoting RegisterPeer(IPEndPoint ep)
        {
            IHostRemoting peerHost = (IHostRemoting)Activator.GetObject(typeof(IHostRemoting),
                    String.Format("tcp://{0}/{1}", ep.ToString(), RemotingURI));
            System.Diagnostics.Debug.Assert(peerHost != null);

            peers.AddOrUpdate(ep, peerHost, (k, v) => v);
            return peerHost;
        }

        public static IHostRemoting GetPeer(IPEndPoint ep)
        {
            if (!peers.ContainsKey(ep))
            {
                return RegisterPeer(ep);
            }
            else
            {
                return peers[ep];
            }
        }

        public static void DispatchActorTo(IActor anActor, IPEndPoint ep)
        {
            anActor.Deactivate();

            IHostRemoting peerHost = GetPeer(ep);
            string asmName = anActor.GetType().Assembly.GetName().FullName;
            try
            {

                if (!peerHost.Understand(asmName))
                {
                    byte[] bytes = LocalFacade.RetrieveAssemblyBytes(asmName);
                    peerHost.DispatchAssemblyTo(asmName, bytes);
                }
            }
            catch (Exception /*ex*/)
            {
                throw;
            }

            peerHost.DispatchTo(anActor);
        }

        public const string RemotingURI = "NIF.MobileActors.Hosts.RemotingHost";
        private static ConcurrentDictionary<IPEndPoint, IHostRemoting> peers = new ConcurrentDictionary<IPEndPoint, IHostRemoting>();
        private static IHostLocal localFacade = null;
    }
}
